package com.sc.nft.annotation;

import cn.hutool.core.convert.Convert;
import com.sc.nft.config.properties.UserRequestRecordConfig;
import com.sc.nft.entity.UserInfo;
import com.sc.nft.enums.RedisKeyEnum;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.pool.UserPool;
import com.sc.nft.sup.ErrorCode;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Aspect
@Component
@Slf4j
public class UserRecordTimesHandler {
    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private UserRequestRecordConfig userRequestRecordConfig;

    @Around("@annotation(userRecordTimes)")
    public Object around(ProceedingJoinPoint joinPoint, UserRecordTimes userRecordTimes) throws Throwable {
        if (!userRequestRecordConfig.getIsOpen()) {
            return joinPoint.proceed();
        }
        UserInfo user = UserPool.getUser();
        if (Objects.isNull(user)) {
            return joinPoint.proceed();
        }
        //获取请求接口路径
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        String requestURI = "";
        if(!Objects.isNull(requestAttributes)){
            HttpServletRequest request = requestAttributes.getRequest();
            requestURI = request.getRequestURI();
        }
        log.debug("用户请求环绕通知,获取Redis锁开始");
        String userRequestPreValue = RedisKeyEnum.USER_REQUEST_PRE_VALUE.getKey() + user.getId() + requestURI;
        String userIllegalRecordTimes = RedisKeyEnum.USER_ILLEGAL_RECORD_TIMES.getKey() + user.getId() + requestURI;
        Boolean userRequestPreValueExist = redisTemplate.hasKey(userRequestPreValue);
        //check越权请求
        if (Boolean.TRUE.equals(userRequestPreValueExist)) {
            //当前请求存在越权 key3记录 key2前置拦截
            redisTemplate.opsForValue().increment(userIllegalRecordTimes);
            redisTemplate.expire(userIllegalRecordTimes, 2, TimeUnit.DAYS);
            throw new GlobalRunTimeException(ErrorCode.FREQUENT_REQUEST);
        }
        String userRequest = RedisKeyEnum.USER_REQUEST.getKey() + user.getId() + requestURI;
        //用户第一次请求
        Boolean userRequestExist = redisTemplate.hasKey(userRequest);
        redisTemplate.opsForValue().increment(userRequest);
        if (!Boolean.TRUE.equals(userRequestExist)) {
            redisTemplate.expire(userRequest, Long.parseLong(userRequestRecordConfig.getValueForExpire()), TimeUnit.SECONDS);
        }
        int valueForRequest = Convert.toInt(redisTemplate.opsForValue().get(userRequest));
        //一分钟请求超过四十次进行记录落库 返回错误码
        if (Convert.toInt(userRequestRecordConfig.getValueForRecord()) < valueForRequest) {
            //达到阈值 生成key2标志位
            redisTemplate.opsForValue().increment(userRequestPreValue);
            redisTemplate.expire(userRequestPreValue, 2, TimeUnit.DAYS);
            throw new GlobalRunTimeException(ErrorCode.FREQUENT_REQUEST);
        }
        return joinPoint.proceed();
    }

}
